package com.glodon.jcloud.increment.shorturl.filter;

import cn.hutool.core.util.StrUtil;
import com.glodon.jcloud.common.api.ApiStatus;
import com.glodon.jcloud.common.api.Status;
import com.glodon.jcloud.common.exception.ApiException;
import com.glodon.jcloud.increment.shorturl.entities.OAuth2Client;
import com.glodon.jcloud.increment.shorturl.security.TokenUtils;
import com.glodon.jcloud.increment.shorturl.service.OAuth2ClientService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.support.RequestContext;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @description:
 * @version: 4.4.0-202312.1-RELEASE-GUIZHOU
 * @author: lib-o
 * @mail: lib-o@glodon.com
 * @create: 2024/5/4 15:48
 */
@Slf4j
public class BasicAuthFilter implements Filter {

    private OAuth2ClientService oAuth2ClientService;

    private String[] excludeUrl = null;

    public BasicAuthFilter(OAuth2ClientService oAuth2ClientService) {
        this.oAuth2ClientService = oAuth2ClientService;
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        String str = config.getInitParameter("excludeUrl");
        if (str != null && !str.trim().isEmpty()) {
            excludeUrl = str.split(",");
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        try {
            if (exclude(request)) {
                filterChain.doFilter(request, response);
                return;
            }

            String token = request.getHeader("token");
            if (StrUtil.isBlank(token)) {
                token = request.getParameter("token");
            }
            if (StrUtil.isBlank(token)) {
                log.warn("access token is empty");
                responseException(response, HttpStatus.UNAUTHORIZED);
                return;
            }

            Map<String, String> params = TokenUtils.decodeToken(token.toString());
            if (null != params) {
                String clientId = params.get("client_id");
                String clientSecret = params.get("client_secret");
                OAuth2Client client = oAuth2ClientService.getByClientidAndClientsecure(clientId, clientSecret);

                if (null != client) {
                    log.info("client info: " + client);
                    // TODO: save context
                } else {
                    log.error("没有匹配到客户端: " + client);
                    responseException(response, HttpStatus.UNAUTHORIZED);
                }
            } else {
                log.error("TOKEN已过期: " + token.toString());
                responseException(response, HttpStatus.EXPECTATION_FAILED);//集采6.0用了短信客户端，识别code=29011时，刷新AccessToken对象
                return;
            }

            log.info("校验授权成功");
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            log.error("校验授权失败", e);
            response.sendError(403, "Forbidden");
        }
    }

    private boolean exclude(HttpServletRequest req) {
        if (null == excludeUrl || excludeUrl.length == 0)
            return false;

        String reqUrl = req.getRequestURI();
        for (String url : excludeUrl) {
            if (reqUrl.contains(url)) {
                log.info("jcloud openapi 当前请求" + reqUrl + "不需要安全认证,允许访问！");
                return true;
            }
        }
        //添加正则匹配 白名单，避免同类请求多次配置
//        for (String url : excludeUrlPatterns) {
//            if (antMatcher.match(url, reqUrl)) return true;
//        }

        return false;
    }

    private void responseException(HttpServletResponse response, HttpStatus status) {
        try {
            response.sendError(status.value(), status.getReasonPhrase());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
